use core::ptr::NonNull;

use acpi::{AcpiHandler, AcpiTables, PciConfigRegions, PhysicalMapping};
use alloc::{alloc::Global, boxed::Box};
use spin::Once;

#[derive(Clone)]
struct UsrMemHandler;

impl AcpiHandler for UsrMemHandler {
    unsafe fn map_physical_region<T>(
        &self,
        physical_address: usize,
        size: usize,
    ) -> PhysicalMapping<Self, T> {
        unistd::mm::mmap(physical_address, size, 0, 0x7);
        unsafe {
            PhysicalMapping::new(
                physical_address,
                NonNull::new_unchecked(physical_address as *mut T),
                size,
                size,
                self.clone(),
            )
        }
    }

    fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
}

pub struct AcpiInfo<'a> {
    pub pci_config_regions: PciConfigRegions<'a, Global>,
}

pub static ACPI_INFO: Once<AcpiInfo> = Once::new();

pub fn init(rsdp_addr: usize) {
    ACPI_INFO.call_once(|| {
        let tables = Box::leak(Box::new(unsafe {
            AcpiTables::from_rsdp(UsrMemHandler, rsdp_addr).unwrap()
        }));

        AcpiInfo {
            pci_config_regions: PciConfigRegions::new(tables).unwrap(),
        }
    });
}
